package com.zensun.system.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zensun.common.enums.domain.SysDictEnum;
import com.zensun.common.utils.Assert;
import com.zensun.system.domain.SysDictData;
import com.zensun.system.domain.SysDictType;
import com.zensun.system.domain.dto.SysDictTypeDto;
import com.zensun.system.domain.vo.SysDictDataSelectVo;
import com.zensun.system.domain.vo.SysDictDataVo;
import com.zensun.system.domain.vo.SysDictTypeSelectVo;
import com.zensun.system.domain.vo.SysDictTypeVo;
import com.zensun.system.mapper.SysDictDataMapper;
import com.zensun.system.mapper.SysDictTypeMapper;
import com.zensun.system.service.ISysDictTypeService;
import com.zensun.system.util.DictUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典 业务层处理
 *
 * @author gmk
 */
@Service
public class SysDictTypeServiceImpl extends ServiceImpl<SysDictTypeMapper, SysDictType> implements ISysDictTypeService {
    @Autowired
    private SysDictTypeMapper dictTypeMapper;

    @Autowired
    private SysDictDataMapper dictDataMapper;

    /**
     * 项目启动时，初始化字典到缓存
     */
    @PostConstruct
    public void init() {
        //所有的字典类型
        List<SysDictType> dictTypeList = this.list();
        LambdaQueryWrapper<SysDictData> q = new LambdaQueryWrapper<>();
        //所有的字典数据
        List<SysDictData> dictDataList = dictDataMapper.selectList(q);
        //转换为Map
        Map<String, List<SysDictData>> dictDataMap = dictDataList.stream().collect(Collectors.groupingBy(SysDictData::getDictType));
        for (SysDictType dictType : dictTypeList) {
            List<SysDictData> dictDataListTemp = dictDataMap.get(dictType.getDictType());
            if (!CollUtil.isEmpty(dictDataListTemp)) {
                List<SysDictDataVo> dictDataRedisList = dictDataListTemp.stream()
                        .map(sysDictData -> {
                            SysDictDataVo sysDictDataVo = new SysDictDataVo();
                            BeanUtils.copyProperties(sysDictData, sysDictDataVo);
                            return sysDictDataVo;
                        })
                        .sorted(Comparator.comparing(SysDictDataVo::getDictSort))
                        .collect(Collectors.toList());
                DictUtils.setDictCache(dictType.getDictType(), dictDataRedisList);
            }

        }
    }

    /**
     * 根据条件分页查询字典类型
     *
     * @param dictTypeDto 字典类型信息
     * @return 字典类型集合信息
     */
    @Override
    public List<SysDictTypeVo> selectDictTypeList(SysDictTypeDto dictTypeDto) {
        return dictTypeMapper.selectDictTypeList(dictTypeDto);
    }

    @Override
    public SysDictTypeVo selectDictTypeId(Long dictId) {
        SysDictType byId = this.getById(dictId);
        SysDictTypeVo sysDictTypeVo = new SysDictTypeVo();
        BeanUtils.copyProperties(byId, sysDictTypeVo);
        return sysDictTypeVo;
    }

    @Override
    public List<SysDictDataSelectVo> getDictDataByDictType(String dictType) {
        // 1.缓存中有直接返回
        List<SysDictDataVo> dictDatas = DictUtils.getDictCache(dictType);
        if (CollUtil.isNotEmpty(dictDatas)) {
            return dictDatas.stream()
                    .filter(sysDictDataVo -> SysDictEnum.DictDataStatus.NORMAL.getCode().equals(sysDictDataVo.getStatus()))
                    .map(sysDictDataVo -> {
                        SysDictDataSelectVo sysDictDataSelectVo = new SysDictDataSelectVo();
                        sysDictDataSelectVo.setDictValue(sysDictDataVo.getDictValue());
                        sysDictDataSelectVo.setDictLabel(sysDictDataVo.getDictLabel());
                        return sysDictDataSelectVo;
                    }).collect(Collectors.toList());
        }
        // 2.缓存中没有查询数据库
        QueryWrapper<SysDictData> queryWrapper = new QueryWrapper<SysDictData>();
        queryWrapper.eq("dict_type", dictType);
        queryWrapper.orderByAsc("dict_sort");
        List<SysDictData> dictDataList = dictDataMapper.selectList(queryWrapper);
        dictDatas = CollStreamUtil.toList(dictDataList, sysDictData -> {
            SysDictDataVo sysDictDataVo = new SysDictDataVo();
            BeanUtils.copyProperties(sysDictData, sysDictDataVo);
            return sysDictDataVo;
        });
        //返回值
        List<SysDictDataSelectVo> results = dictDatas.stream()
                .filter(s -> SysDictEnum.DictDataStatus.NORMAL.getCode().equals(s.getStatus()))
                .map(sysDictData -> {
                    SysDictDataSelectVo sysDictDataSelectVo = new SysDictDataSelectVo();
                    sysDictDataSelectVo.setDictValue(sysDictData.getDictValue());
                    sysDictDataSelectVo.setDictLabel(sysDictData.getDictLabel());
                    return sysDictDataSelectVo;
                }).collect(Collectors.toList());
        // 3.更新缓存
        if (CollUtil.isNotEmpty(dictDatas)) {
            DictUtils.setDictCache(dictType, dictDatas);
            return results;
        }
        return null;
    }

    /**
     * 批量删除字典类型信息
     *
     * @param dictIds 需要删除的字典ID
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteDictTypeByIds(Long[] dictIds) {

        Assert.isEmpty(Arrays.asList(dictIds), "请选择字典类型");
        //查询删除的字典类型 得到dictType
        List<SysDictType> sysDictTypeList = dictTypeMapper.selectBatchIds(Arrays.asList(dictIds));
        List<String> sysDictTypes = CollStreamUtil.toList(sysDictTypeList, SysDictType::getDictType);
        //1.删除字典数据
        LambdaQueryWrapper<SysDictData> q = new LambdaQueryWrapper<>();
        q.in(SysDictData::getDictType, sysDictTypes);
        List<Long> sysDictDataIdList = CollStreamUtil.toList(dictDataMapper.selectList(q), SysDictData::getDictCode);
        if(CollUtil.isNotEmpty(sysDictDataIdList)){
            dictDataMapper.deleteBatchIds(sysDictDataIdList);
        }
        //2.删除字典类型
        if (dictTypeMapper.deleteBatchIds(Arrays.asList(dictIds)) > 0) {
            for (String sysDictType : sysDictTypes) {
                DictUtils.deleteDictCache(sysDictType);
            }
        }
        return true;
    }

    /**
     * 清空缓存数据
     */
    @Override
    public void clearCache() {
        DictUtils.clearDictCache();
    }

    /**
     * 新增保存字典类型信息
     *
     * @param dict 字典类型信息
     * @return 结果
     */
    @Override
    public int insertDictType(SysDictType dict) {
        // 1.校验
        Assert.isTrue(!checkDictTypeUnique(dict), "修改字典'" + dict.getDictType() + "'失败，字典类型已存在");
        // 2.插入成功
        return dictTypeMapper.insert(dict);
    }

    /**
     * 修改保存字典类型信息
     *
     * @param dict 字典类型信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDictType(SysDictType dict) {
        // 1.校验
        Assert.isTrue(!checkDictTypeUnique(dict), "修改字典'" + dict.getDictType() + "'失败，字典类型已存在");
        // 2.数据准备
        SysDictType oldDict = dictTypeMapper.selectById(dict.getDictId());
        // 3.更新SysDictType,清空字典缓存
        int row = dictTypeMapper.updateById(dict);
        if (row > 0) {
            DictUtils.deleteDictCache(oldDict.getDictType());
        }
        return row;
    }

    @Override
    public List<SysDictTypeSelectVo> optionselect() {
        return CollStreamUtil.toList(this.list(), sysDictType -> {
            SysDictTypeSelectVo vo = new SysDictTypeSelectVo();
            BeanUtils.copyProperties(sysDictType, vo);
            return vo;
        });
    }

    /**
     * 校验字典类型称是否唯一
     *
     * @param dict 字典类型
     * @return 结果
     */
    public boolean checkDictTypeUnique(SysDictType dict) {
        boolean result = true;
        //增加或者修改
        Long dictId = ObjectUtil.isNull(dict.getDictId()) ? -1L : dict.getDictId();
        //字典类型
        String dictType = dict.getDictType();
        // 1.根据字典类型查询数据库是否存在此字典类型
        LambdaQueryWrapper<SysDictType> q = new LambdaQueryWrapper<>();
        q.eq(SysDictType::getDictType, dictType);
        SysDictType one = this.getOne(q);
        if (ObjectUtil.isNotEmpty(one) && !one.getDictId().equals(dictId)) {
            result = false;
        }
        return result;
    }
}
